package com.jmp.security.grant.crmApp;

import com.jmp.base.dto.AccountResponse;
import com.jmp.feign.MessageFeign;
import com.jmp.security.base.ClientDetail;
import com.jmp.security.base.RequestDetail;
import com.jmp.security.base.UserDetail;
import com.jmp.security.base.UserDetailService;
import com.jmp.base.dto.ClientEnum;
import com.jmp.security.grant.wx.WxLoginService;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import one.stand.advice.ResultEnum;
import one.stand.dto.WechatLoginDto;
import one.stand.dto.WechatUserInfoDto;
import one.stand.enums.LoginEnum;
import one.stand.model.User;
import one.stand.service.UserService;
import one.stand.service.user.UserAdminService;
import one.stand.util.AssertUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.Objects;

@Slf4j
public class CrmAppWx2UserDetailServiceImpl implements UserDetailService<CrmAppWx2UserDetailServiceImpl.Wx2CodeRequestDetail> {
    private UserAdminService userAdminService;
    private WxLoginService wxLoginService;
    private UserService userService;

    public CrmAppWx2UserDetailServiceImpl(UserAdminService userAdminService, WxLoginService wxLoginService, MessageFeign messageFeign, UserService userService) {
        this.userAdminService = userAdminService;
        this.wxLoginService = wxLoginService;
        this.userService = userService;
    }

    @Override
    public UserDetail get(Wx2CodeRequestDetail requestDetail, ClientDetail clientDetail) {
        WxUserDetail userDetail = new WxUserDetail();
        codeOauth(requestDetail, clientDetail, userDetail);

        if (Objects.isNull(userDetail.getUserModel())) {
            saveUser(clientDetail.getCompanyAccountModel().getCompanyId(), userDetail);
        } else {
            updateUser(requestDetail, userDetail);
        }

        userService.saveUserLoginWx(userDetail.getUserModel().getUserId(), requestDetail.getLoginEnum().getAccountType(),
                requestDetail.getCompanyKey(), userDetail.getWechatLoginDto().getOpenId());

        User inModel = userAdminService.getByUserId(userDetail.getUserModel().getUserId());//重新获取最新User信息
        userDetail.setUserModel(inModel);
        userDetail.setSessionKey(userDetail.getWechatLoginDto().getSessionKey());
        return userDetail;
    }

    private void updateUser(Wx2CodeRequestDetail request, WxUserDetail userDetail) {
        User inModel = userDetail.getUserModel();
        WechatLoginDto wechatLoginDto = userDetail.getWechatLoginDto();
        WechatUserInfoDto userInfoDto = userDetail.getUserInfoDto();

        User userModel = new User();
        if (StringUtils.isBlank(inModel.getUnionid())
                && StringUtils.isNoneBlank(wechatLoginDto.getUnionId())) {
            userModel.setUserId(inModel.getUserId());
            userModel.setUnionid(wechatLoginDto.getUnionId());
        }
        final boolean isUpdateUserInfo = userAdminService.isVisit(inModel.getAvatarUrl()) && Objects.nonNull(userInfoDto);
        if (isUpdateUserInfo) {
            userModel.setUserId(inModel.getUserId());
            userModel.setNickeName(userInfoDto.getNickName());
            userModel.setAvatarUrl(userInfoDto.getAvatarUrl());
            userModel.setGender(userInfoDto.getGender());
            userModel.setCity(userInfoDto.getCity());
            userModel.setProvince(userInfoDto.getProvince());
            userModel.setCountry(userInfoDto.getCountry());
        }
        if (StringUtils.isBlank(inModel.getOpenId())) {
            userModel.setUserId(inModel.getUserId());
            userModel.setOpenId(wechatLoginDto.getOpenId());

            userService.deleteByOpenId(wechatLoginDto.getOpenId());
        }
        if (Objects.nonNull(userModel.getUserId())) {
            userService.update(userModel);
        }

        if (StringUtils.isNoneBlank(wechatLoginDto.getOpenId())) {
            userService.saveUserLoginWx(inModel.getUserId(), request.getLoginEnum().getAccountType(), request.getCompanyKey(), wechatLoginDto.getOpenId());
        }
    }

    private void saveUser(Integer companyId, WxUserDetail userDetail) {
        User inModel = new User();
        inModel.setUnionid(userDetail.getWechatLoginDto().getUnionId());
        inModel.setEnterpriseId(companyId);
        if (Objects.nonNull(userDetail.getUserInfoDto())) {
            inModel.setNickeName(userDetail.getUserInfoDto().getNickName());
            inModel.setAvatarUrl(userDetail.getUserInfoDto().getAvatarUrl());
            inModel.setGender(userDetail.getUserInfoDto().getGender());
            inModel.setCity(userDetail.getUserInfoDto().getCity());
            inModel.setProvince(userDetail.getUserInfoDto().getProvince());
            inModel.setCountry(userDetail.getUserInfoDto().getCountry());
        }
        inModel.setOpenId(userDetail.getWechatLoginDto().getOpenId());
        userService.saveUser(inModel);

        userDetail.setUserModel(inModel);
    }

    private void codeOauth(Wx2CodeRequestDetail request, ClientDetail clientDetail, WxUserDetail userDetail) {
        AccountResponse companyAccountModel = clientDetail.getCompanyAccountModel();
        WechatLoginDto wechatLoginDto = wxLoginService.loginBack(request.getCode(), companyAccountModel.getAppId(), companyAccountModel.getAppSecret());
        WechatUserInfoDto userInfoDto = null;
        if (StringUtils.isNoneBlank(request.getEncrypteData())) {
            userInfoDto = wxLoginService.getUserInfo(request.getEncrypteData(), wechatLoginDto.getSessionKey(), request.getIv());
        }
        if (StringUtils.isNoneBlank(wechatLoginDto.getUnionId()) && Objects.nonNull(userInfoDto)) {
            wechatLoginDto.setUnionId(userInfoDto.getUnionid());
        }
        if (Objects.isNull(userInfoDto) && StringUtils.isNoneBlank(wechatLoginDto.getAccessToken()) && StringUtils.isNoneBlank(wechatLoginDto.getOpenId())) {
            userInfoDto = wxLoginService.getUserInfo(wechatLoginDto.getAccessToken(), wechatLoginDto.getOpenId());
        }

        User inModel = userService.getByWx(wechatLoginDto.getUnionId(), request.getLoginEnum(), request.getCompanyKey(), wechatLoginDto.getOpenId());

        userDetail.setWechatLoginDto(wechatLoginDto);
        userDetail.setUserInfoDto(userInfoDto);
        userDetail.setUserModel(inModel);
    }

    @Data
    @EqualsAndHashCode(callSuper = true)
    public static class WxUserDetail extends UserDetail {
        private WechatLoginDto wechatLoginDto;
        private WechatUserInfoDto userInfoDto;
    }

    @Data
    @Builder
    public static class Wx2CodeRequestDetail implements RequestDetail {

        private ClientEnum clientEnum;
        private String pushCid;
        /**
         * 登陆程序名
         */
        private LoginEnum loginEnum;
        /**
         * 登陆client key
         */
        private String companyKey;
        /**
         * 微信小程序登录、 微信公众号登录
         */
        private String code;
        /**
         * 用户敏感信息
         */
        private String encrypteData;
        /**
         * 解密算法的向量
         */
        private String iv;

        @Override
        public String getEquCode() {
            return null;
        }

        @Override
        public Integer getEquCodeType() {
            return null;
        }

        @Override
        public void initAfter() {
            AssertUtil.nonNull(loginEnum, ResultEnum.PARAM_CHECK);
            AssertUtil.nonNull(companyKey, ResultEnum.PARAM_CHECK);
            AssertUtil.nonNull(code, ResultEnum.PARAM_CHECK);
        }
    }
}
